package Robots;

// Bereitstellen der Einheitenumrechnungen
import HelpingClasses.PhysikEinheiten;

/**
 * <strong>Unterklasse von MobileRoboter</strong><br />
 * Eine Instanz vom SchwimmRoboter (im Folgenden "schwimmende Roboter") ist zunaechst
 * einmal ein Roboter bzw. MobilerRoboter (Superklasse), hat aber weitere Eigenschaften
 * wie Masse (Breite, Hoehe, Lanege), ein Gewicht sowie eine Ladungskapazitaet.
 * @author Torbjoern Klatt
 */
public class SchwimmRoboter extends MobileRoboter {
    // Instanzvariablen
    private double breite, hoehe, laenge, gewicht, ladung_max, ladung_current;
    
    //*******************************
    // Konstruktoren
    /**
     * erzeugt ein Objekt vom Typ SchwimmRoboter
     * @param s Name
     * @param bj Baujahr
     * @param tempo_max maximale Geschwindigkeit in Meter/Sekunde; wenn kleiner gleich 0 => 1
     * @param tnk_max maximales Tankvolumen in Liter; wenn kleiner gleich 0 => 1
     * @param verb Verbrauch in Liter/Kilometer; wenn kleiner gleich 0 => 1
     * @param b Breite
     * @param h Hohe
     * @param l Laenge
     * @param g Gewicht
     * @param lad_max maximale Ladungskapazitaet
     */
    public SchwimmRoboter(String s, int bj, double tempo_max, double tnk_max, double verb,
            double b, double h, double l, double g, double lad_max) {
        super(s, bj, tempo_max, tnk_max, verb);
        this.breite = b;
        this.hoehe = h;
        this.laenge = l;
        this.gewicht = g;
        this.ladung_max = lad_max;
    }
    
    //*******************************
    // Getter
    /**
     * @return Breite
     */
    public double getBreite() {
        return breite;
    }

    /**
     * @return Gewicht
     */
    public double getGewicht() {
        return gewicht;
    }

    /**
     * @return Hoehe
     */
    public double getHoehe() {
        return hoehe;
    }

    /**
     * @return genutzte Ladungskapazitaet
     */
    public double getLadung_current() {
        return ladung_current;
    }

    /**
     * @return maximale Ladungskapazitaet
     */
    public double getLadung_max() {
        return ladung_max;
    }
    
    /**
     * @return freie Ladungskapazitaet
     */
    public double getLadung_remaining() {
        return ladung_max-ladung_current;
    }

    /**
     * @return Laenge
     */
    public double getLaenge() {
        return laenge;
    }
    
    //*******************************
    // Setter    
    /**
     * @param breite Breite
     */
    public void setBreite(double breite) {
        this.breite = breite;
    }

    /**
     * @param gewicht Gewicht
     */
    public void setGewicht(double gewicht) {
        this.gewicht = gewicht;
    }

    /**
     * @param hoehe Hoehe
     */
    public void setHoehe(double hoehe) {
        this.hoehe = hoehe;
    }

    /**
     * @param ladung_current genutzte Ladungskapazitaet
     */
    public void setLadung_current(double ladung_current) {
        this.ladung_current = ladung_current;
    }
    
    /**
     * @param laenge Laenge
     */
    public void setLaenge(double laenge) {
        this.laenge = laenge;
    }
    
    //*******************************
    // Instanzmethoden
    /**
     * Berechnet den neuen Tankfuellstand nach Zuruecklegen der Distanz bei aktuellem Tempo
     * in der angegebenen Zeit und gibt kurze Statusmeldung in Stdout aus.
     * @param t Zeit in Stunden
     */
    @Override
    public void moveForHours(double t) {
        PhysikEinheiten physein = new PhysikEinheiten(this.getTempo_current(), 0, t);
        System.out.println("Es wird versucht sich "+df.format(t)+"h lang fortzubwegen.");
        // zu zuruecklegende Distanz nach der Zeit und gegenwaertigem Tempo berechnen
        physein.setKmeter(physein.ms2kmh()*physein.getH());
        // noch genuegend Treibstoff vorhanden
        if(t >= this.getLaufzeit_remaining()) {
            // zurueckgelegte Distanz und benoetigte Zeit ausgeben
            System.out.println("Es wurden "+df.format(physein.getKmeter())+" Kilometer " +
                    "in "+df.format(t)+" Stunden zureuckgelegt.");
            // neuen Tankfuellstand berechnen
            this.setTank_current(this.getTank_current()-(this.getVerbrauch()*
                    physein.getKmeter()));
            // und Tenkfuellstand ueberpruefen
            this.checkTank();
        }
        // zu wenige Treibstoff
        else {
            // zurueckgelegte Distanz berechnen
            physein.setKmeter(this.getReichweite_remaining());
            // Tankfuellstand entsprechend setzen und Meldung ausgeben
            this.setTank_current(0);
            System.out.println("Zu wenig Treibstoff fuer angestrebte Laufzeit." +
                    " Es wurden "+df.format(physein.getKmeter())+" Kilometer in "
                    +df.format(physein.getH())+" Stunden zurueckgelegt.");
            // Tankfuellstand ueberpruefen
            this.checkTank();
        }
    }
    
    /**
     * Berechnet den neuen Tankfuellstand nach zuruecklegen der angegebenen Kilometern,
     * die benoetigte Zeit und gibt kurze Statusmeldung in Stdout aus.
     * @param d Distanz in Kilometer
     */
    @Override
    public void moveForDistance(double d) {
        PhysikEinheiten physein = new PhysikEinheiten(this.getTempo_current(), d, 0);
        System.out.println("Es wird versucht "+df.format(d)+"km zurueckzulegen.");
        // benoetigte Zeit berechnen
        physein.setH(d/this.getTempo_current());
        // noch genuegend Treibstoff vorhanden
        if(d <= this.getReichweite_remaining()) {
            // zurueckgelegte Distanz und benoetigte Zeit ausgeben
            System.out.println("Es wurden "+df.format(d)+" Kilometer " +
                    "in "+df.format(physein.getH())+" Stunden zureuckgelegt.");
            // neuen Tankfuellstand berechnen
            this.setTank_current(this.getTank_current()-(this.getVerbrauch()*d));
            // und Tenkfuellstand ueberpruefen
            this.checkTank();
        }
        // zu wenig Treibstoff
        else {
            // zurueckgelegte Distanz berechnen
            d = this.getReichweite_remaining();
            // Tankfuellstand entsprechend setzen und Meldung ausgeben
            System.out.println("Zu wenig Treibstoff fuer angestrebte Distanz. Es wurden "+
                    df.format(d)+" Kilometer in "+df.format(this.getLaufzeit_remaining())
                    +" Stunden zurueckgelegt.");
            this.setTank_current(0);
            // Tankfuellstand ueberpruefen
            this.checkTank();
        }
    }
    
    /**
     * @return String mit name, baujahr, status, gegenwaertigem und maximalem Tempo,
     * gegenwaertigem Tankfuellstand und maximalem Tankvolumen, Verbrauch, verbleibende
     * Laufzeit und maximale Reichweite
     */
    @Override
    public String toString() {
        return "Mobiler Roboter:\n\tName: "+this.getName()
                +"\n\tID: "+this.getID()
                +"\n\tBaujahr: "+this.getBaujahr()
                +"\n\tEin/Aus: "+this.isOn()
                +"\n\tMasse (B/H/L): "+df.format(this.breite)+"/"+df.format(this.hoehe)
                    +"/"+df.format(this.laenge)
                +"\n\tTempo: "+df.format(this.getTempo_current())+"m/s / "
                    +df.format(this.getTempo_max())+"m/s"
                +"\n\tTank: "+df.format(this.getTank_current())+"L / "
                    +df.format(this.getTank_max())+"L"
                +"\n\tVerbrauch: "+df.format(this.getVerbrauch())+"L/km"
                +"\n\tLaufzeit: "+df.format(this.getLaufzeit_remaining())+"h"
                +"\n\tReichweite: "+df.format(this.getReichweite_remaining())+"km / "
                    +df.format(this.getReichweite_max())+"km"
                +"\n\tLadung: "+df.format(this.ladung_current)+"/"
                    +df.format(this.ladung_max);
    }

    /**
     * @param obj
     * @return true wenn obj vom Typ MobileRoboter ist und sowohl Name, Baujahr, 
     * Tankvolumen, maximales Temp, Verbrauch, Gewicht, Breite, Hoehe, Laenge und
     * maximale Ladungskapazitaet identisch sind, sonst false
     */
    @Override
    public boolean equals(Object obj) {
        if(obj instanceof SchwimmRoboter &&
                this.getName().equals(((SchwimmRoboter)obj).getName()) &&
                this.getBaujahr() == ((SchwimmRoboter)obj).getBaujahr() &&
                this.getTank_max() == ((SchwimmRoboter)obj).getTank_max() &&
                this.getTempo_max() == ((SchwimmRoboter)obj).getTempo_max() &&
                this.getVerbrauch() == ((SchwimmRoboter)obj).getVerbrauch() &&
                this.gewicht == ((SchwimmRoboter)obj).gewicht &&
                this.breite == ((SchwimmRoboter)obj).breite &&
                this.hoehe == ((SchwimmRoboter)obj).hoehe &&
                this.laenge == ((SchwimmRoboter)obj).laenge &&
                this.ladung_max == ((SchwimmRoboter)obj).ladung_max) {
            return true;
        }
        else {
            return false;
        }
    }

    /**
     * @return einen Hashcode fuer diesen SchwimmRoboter
     */
    @Override
    public int hashCode() {
        int hash = 5;
        hash = 89 * hash + (int) (Double.doubleToLongBits(this.breite) ^
                (Double.doubleToLongBits(this.breite) >>> 32));
        hash = 89 * hash + (int) (Double.doubleToLongBits(this.hoehe) ^
                (Double.doubleToLongBits(this.hoehe) >>> 32));
        hash = 89 * hash + (int) (Double.doubleToLongBits(this.laenge) ^
                (Double.doubleToLongBits(this.laenge) >>> 32));
        hash = 89 * hash + (int) (Double.doubleToLongBits(this.gewicht) ^
                (Double.doubleToLongBits(this.gewicht) >>> 32));
        hash = 89 * hash + (int) (Double.doubleToLongBits(this.ladung_max) ^
                (Double.doubleToLongBits(this.ladung_max) >>> 32));
        hash = 89 * hash + (int) (Double.doubleToLongBits(this.ladung_current) ^
                (Double.doubleToLongBits(this.ladung_current) >>> 32));
        return hash;
    }
}